/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
    
package be.vdabantwerpen.gow.dao;
    
import be.vdabantwerpen.gow.entities.Post;
import be.vdabantwerpen.gow.entities.Weight;
import be.vdabantwerpen.gow.entities.actions.Action;
import be.vdabantwerpen.gow.entities.actions.FiveStarAction;
import be.vdabantwerpen.gow.entities.actions.FourStarAction;
import be.vdabantwerpen.gow.entities.actions.OneStarAction;
import be.vdabantwerpen.gow.entities.actions.ReplyAction;
import be.vdabantwerpen.gow.entities.actions.ScorePostAction;
import be.vdabantwerpen.gow.entities.actions.ThreeStarAction;
import be.vdabantwerpen.gow.entities.actions.TwoStarAction;
import be.vdabantwerpen.gow.entities.actions.VisitPostAction;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.repackaged.org.joda.time.DateTime;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author tim.vandenlangenberg
 * @version 0.1
 */
public class ActionDAOImpl implements ActionDAO {
    private final DatastoreService datastore = 
            DatastoreServiceFactory.getDatastoreService();
    private final PostDAO postDAO = new PostDAOImpl();
    
    @Override
    public void create(Action action){
        Entity e = toEntity(action);
        datastore.put(e);
    }
    
    @Override
    public Action read(String className){
        Entity e = new Entity("Action", className);
        try { 
            return toAction(datastore.get(e.getKey()));
        }
        catch(EntityNotFoundException enfe){
            return null;
        }
    }
    
    @Override
    public void update(Action action){
        Entity e = toEntity(action);
        datastore.put(e);
    }
    
    @Override
    public void delete(Action action){
        Entity e = toEntity(action);
        datastore.delete(e.getKey());
    }
    
    @Override
    public List<Action> findAll(){
        List<Action> actions = new ArrayList();
        Query q = new Query("Action");
        PreparedQuery pq = datastore.prepare(q);
        for(Entity entity : pq.asIterable()){
            actions.add(toAction(entity));
        }
        return actions;
    }
    
    @Override
    public List<Weight> findWeights(){
        List<Weight> weights = new ArrayList();
        Query q = new Query("Weight");
        PreparedQuery pq = datastore.prepare(q);
        for(Entity entity : pq.asIterable()){
            weights.add(toWeight(entity));
        }
        return weights;
    }
    
    @Override
    public Weight findWeight(String actionName){
        Entity e = new Entity("Weight", actionName);
        try {
            return toWeight(datastore.get(e.getKey()));
        }
        catch(EntityNotFoundException nfe){
            return null;
        }
    }
    
    @Override
    public void updateWeight(Weight weight){
        datastore.put(toEntity(weight));
    }
    
    private Entity toEntity(Action action){
        Entity entity = new Entity("Action", action.getClass().getName());
        entity.setProperty("dateTime", action.getDateTime().toString());
        entity.setProperty("points", action.getPoints());
        if(action instanceof VisitPostAction){
            entity.setProperty("post", ((VisitPostAction)action).getPost().hashCode());
        }
        return entity;
    }
    
    private Entity toEntity(Weight weight){
        Entity entity = new Entity("Weight", weight.getActionType());
        entity.setProperty("actionType", weight.getActionType());
        entity.setProperty("weight", weight.getWeight());
        return entity;
    }
    
    private Action toAction(Entity entity){
        Action action;
        DateTime dateTime;
        if(entity.getProperty("dateTime") == null){
            dateTime = null;
        }
        else {
            dateTime = DateTime.parse(entity.getProperty("dateTime").toString()); 
        }
        int points;
        if(entity.getProperty("points") == null){
            points = 0;
        }
        else {
            points  = Integer.valueOf(entity.getProperty("points").toString());
        }
        Post post;
        if(entity.getProperty("post") == null){
            post = null;
        }
        else {
            post = postDAO.read(Integer.valueOf(entity.getProperty("post").toString()));
        }
        if(entity.getKey().getName().equalsIgnoreCase(VisitPostAction.class.getName())){
            action = new VisitPostAction(points, dateTime, post);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(ReplyAction.class.getName())){
            action = new ReplyAction(points, dateTime, post);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(ScorePostAction.class.getName())){
            action = new ScorePostAction(points, dateTime);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(OneStarAction.class.getName())){
            action = new OneStarAction(points, dateTime);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(TwoStarAction.class.getName())){
            action = new TwoStarAction(points, dateTime);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(ThreeStarAction.class.getName())){
            action = new ThreeStarAction(points, dateTime);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(FourStarAction.class.getName())){
            action = new FourStarAction(points, dateTime);
        }
        else if(entity.getKey().getName().equalsIgnoreCase(FiveStarAction.class.getName())){
            action = new FiveStarAction(points, dateTime);
        }
        else {
            action = null;
        }
        return action;
    }
    
    private Weight toWeight(Entity e){
        String actionType = (String)e.getProperty("actionType");
        int weight = Integer.valueOf(e.getProperty("weight").toString());
        return new Weight(actionType, weight);
    }
    
}